# coding: utf-8

import time
import datetime
import json

from sqlalchemy import text

from .extensions import db
from .constant import expression_dict


def get_timestamp():
    return int(time.time())


def get_timestamp_ms():
    return int(time.time() * 1000)


def get_today_begin_timestamp():
    return int(time.mktime(datetime.date.today().timetuple()))


class AbstractModel(db.Model):
    """
    create by ld_wu 2017-11-10
    model基类，定义公用方法
    """

    __abstract__ = True

    search_keys = ()

    json_keys = {}

    # 每个model需要覆写此字段, 用于标明哪些字段可过滤搜索
    # key代表的是前端传过来的参数名
    # value是一个元组, 第一位是DB对应字段名, 第二位是运算符
    # 若value为空元组, 则DB对应字段名默认等于key, 运算符默认为=
    filter_dict = {}

    # 每个model需要覆写此字段, 用于标明哪些字段可排序
    order_keys = ()

    # 默认的排序字段
    default_order_key = 'id'

    default_order_asc = False

    @staticmethod
    def flush():
        db.session.flush()

    @classmethod
    def create(cls, **kwargs):
        """
        创建model示例
        """
        _new = cls(**kwargs)
        db.session.add(_new)
        cls.flush()
        return _new

    @classmethod
    def column_set(cls):
        """
        返回表字段名列表
        :return:
        """
        return cls.__table__.c._data._list

    @classmethod
    def self_col_create(cls, **kwargs):
        """
        create by ld_wu 2018-01-04
        插入过滤后只剩表字段的数据
        """
        columns = [col for col in cls.column_set() if col != 'id']
        data = {
            key: value for key, value in kwargs.items() if key in columns
        }
        if 'created_at' in data:
            data['created_at'] = data['created_at'] or get_timestamp()

        if 'updated_at' in data:
            data['updated_at'] = data['updated_at'] or get_timestamp()
        return cls.create(**data)

    @staticmethod
    def _json_loads(value, type_obj):
        if not value:
            value = type_obj()
        if isinstance(value, str):
            try:
                value = json.loads(value)
            except:
                pass
        return value

    def __setattr__(self, key, value):
        """
        create by ld_wu 2018-01-16
        当设置在json_keys中存在的值的修改为相应对象
        :return:
        """
        if key in self.json_keys:
            value = self._json_loads(value, self.json_keys[key])
        super(AbstractModel, self).__setattr__(key, value)

    @classmethod
    def generate_search_condition(cls, args):
        """
        生成DB模糊搜索条件与过滤搜索条件
        @:param args: dict
        """
        conditions = None

        # 模糊搜索
        search_keys = cls.search_keys
        for i in search_keys:
            col = getattr(cls, i, None)
            if col and i in args and args[i]:
                cond = col.like('%{}%'.format(args[i]))
                conditions = (
                    cond if conditions is None else (conditions | cond)
                )

        # 过滤搜索
        filter_dict = cls.filter_dict
        for k, v in filter_dict.items():
            args_name = k
            db_field_name = k if not v else v[0]
            operator = '=' if not v else v[1]

            col = getattr(cls, db_field_name, None)
            # 当参数名在args中才生成此条件
            if col and args_name in args:
                cond = expression_dict[operator](col, args[args_name])
                conditions = cond if conditions is None else (conditions & cond)

        return conditions

    @classmethod
    def generate_order_by(cls, args):
        """
        生成DB 排序条件
        """
        # 传入的参数应为: create_time|asc
        order_by = args.get('order_by', None)
        if order_by:
            order_keys = cls.order_keys
            col_info, order_type = order_by.split('|')
            col = getattr(cls, col_info, None)
            if col and col_info in order_keys and order_type in ['asc', 'desc']:
                return col.asc() if order_type == 'asc' else col.desc()
        return (
            getattr(cls, cls.default_order_key).desc()
            if not cls.default_order_asc
            else getattr(cls, cls.default_order_key).asc()
        )

    @classmethod
    def generate_list_query_condition(cls, args, query=None, need_orderby=True):
        """
        生成列表查询的query对象并返回
        """
        query_obj = query or cls.query
        filter_condition = cls.generate_search_condition(args)
        if filter_condition is not None:
            query_obj = query_obj.filter(filter_condition)
        if need_orderby:
            query_obj = query_obj.order_by(cls.generate_order_by(args))
        return query_obj

    @classmethod
    def get_by_id(cls, id):
        """
        created by chenhj at 2017/8/3

        """
        return cls.query.get(id)

    @classmethod
    def get_by_args(cls, **kwargs):
        """
        created by chenhj at 2017/7/26

        """
        return cls.query.filter_by(**kwargs).first()

    @classmethod
    def get_list_by_ids(cls, ids):
        """
        created by chenhj at 2017/8/1

        """
        return cls.query.filter(cls.id.in_(ids))

    @classmethod
    def get_list_by_args(cls, **kwargs):
        """
        created by chenhj at 2017/8/1

        """
        return cls.query.filter_by(**kwargs).all()

    @classmethod
    def remove(cls, query=None, **kwargs):
        """
        create by ld_wu 2018-01-17
        记录软删除
        """
        if query is None:
            query = cls.query
        query = query.filter_by(**kwargs)
        query.update(
            dict(
                deleted_at=get_timestamp()
            ),
            synchronize_session='fetch'
        )

    def update(self, **kwargs):
        """
        add by zhouhl 2017-10-17
        """
        for k, v in kwargs.items():
            setattr(self, k, v)
        self.flush()


class BaseModel(AbstractModel):
    """
    create by zhouhl 2017-07-08
    基类Model，一些共有的字段信息
    """
    __abstract__ = True

    id = db.Column(db.Integer, primary_key=True)
    created_at = db.Column(
        db.Integer, nullable=False, server_default=text("'0'"),
        default=get_timestamp)
    updated_at = db.Column(
        db.Integer, nullable=False, server_default=text("'0'"),
        default=get_timestamp, onupdate=get_timestamp)
    deleted_at = db.Column(
        db.Integer, nullable=False, server_default=text("'0'"), default=0)

    @property
    def created_datetime(self):
        return datetime.datetime.fromtimestamp(self.created_at)

    @property
    def updated_datetime(self):
        return datetime.datetime.fromtimestamp(self.updated_at)

    @property
    def deleted_datetime(self):
        return datetime.datetime.fromtimestamp(self.deleted_at)


class ExtensionalModel(AbstractModel):
    """
    create by ld_wu 2017-11-10
    扩展表，把主表一些不常用的信息放在扩展表中
    """
    __abstract__ = True


